/**
 * Displays OpenCV video on framebuffer.
 * Compile with
 * g++ -o fbwrite_video -lopencv_core -lopencv_highgui -lopencv_imgproc fbwrite_video.cpp
 */

#include <iostream> // for std::cerr
#include <opencv2/opencv.hpp>
#include <fstream> // for std::ofstream
#include <unistd.h>

#include <sys/ioctl.h> // for ioctl
#include <linux/fb.h> // for fb_
#include <fcntl.h> // for O_RDWR

__u32 line_length;   //帧缓冲中一行的字节数 xres_virtual * bits_per_pixel/8

//可以使用fbset -i查看帧缓冲信息
void get_framebuffer_info(const char* framebuffer_device_path) {
    struct fb_var_screeninfo screen_info;  //屏幕信息
    struct fb_fix_screeninfo sfi;          //驱动信息
    int fd = -1;

    fd = open(framebuffer_device_path, O_RDWR);
    ioctl(fd, FBIOGET_VSCREENINFO, &screen_info);
    ioctl(fd, FBIOGET_FSCREENINFO, &sfi);
    line_length = sfi.line_length;
    //打印屏幕分辨率和每像素存储大小
    printf("%dx%d %d\n", screen_info.xres, screen_info.yres, screen_info.bits_per_pixel);
};

//在VM上画面不能自动刷新，需要使用mmap
int main(int, char**) {
    get_framebuffer_info("/dev/fb0");
    cv::VideoCapture cap(0);
    std::ofstream ofs("/dev/fb0");

    cv::Mat frame;
    while (true) {
	    cap >> frame;

	    cv::Size2f frame_size = frame.size();
	    cv::cvtColor(frame, frame, CV_BGR2BGRA); //24bit -> 32bit
	    for (int y = 0; y < frame_size.height ; y++) {
		    ofs.seekp(y * line_length);  //按行写
		    ofs.write(reinterpret_cast<char*>(frame.ptr(y)), frame_size.width*4);
	    }
        ofs.flush();
	    usleep(1000*40);
    }
}
